package com.sunlands.qdcy.tongzhuo.exception;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sunlands.qdcy.tongzhuo.constant.CommonResultMessage;
import com.sunlands.qdcy.tongzhuo.util.DateUtil;
import com.sunlands.qdcy.tongzhuo.util.HttpHelper;
import com.sunlands.qdcy.tongzhuo.vo.BusinessResult;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

import static com.sunlands.qdcy.tongzhuo.constant.CommonResultMessage.*;


/**
 * <p>全局异常处理</p>
 * <PRE>
 * <BR>    修改记录
 * <BR>-----------------------------------------------
 * <BR>    修改日期         修改人          修改内容
 * </PRE>
 *
 * @author zl
 * @version 1.0
 * @date Created in 2019/3/15 12:00
 * @copyright: Copyright (c) founders
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    @Autowired
    private SendExceptionUtil sendExceptionUtil;

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 参数异常处理
     *
     * @param exception
     * @return
     */
    @ExceptionHandler({CheckParamException.class})
    public ResponseEntity<BusinessResult<Object>> handleParamException(CheckParamException exception) {
        logger.error("【handleParamException】：" + exception.getMessage());
        BusinessResult<Object> businessResult = BusinessResult.createInstance(PARMAS_INVALID.getCode(), exception.getMessage());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(businessResult);
    }

    /**
     * 业务异常处理
     *
     * @param e
     * @return
     */
    @ExceptionHandler({BusinessException.class})
    public ResponseEntity<BusinessResult<Object>> handleBusinessException(HttpServletRequest request, BusinessException e) {
        String method = request.getMethod();
        String uri = request.getRequestURI();
        String paramInfo = "";
        paramInfo = getParam(request, method, paramInfo);
        log.error("API: excepiton={} cause={} method={} uri={} paramInfo={}", e.getClass().getSimpleName(), e.getMessage(), method, uri, paramInfo);
        log.error("", e);
        formatException(e, method, uri, paramInfo);
        BusinessResult<Object> businessResult = BusinessResult.createInstance(DIARY_FAIL.getCode(), e.getMessage());
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(businessResult);
    }

    /**
     * 参数异常
     *
     * @param exception
     * @return
     */
    @ExceptionHandler({IllegalArgumentException.class})
    public ResponseEntity<BusinessResult<Object>> handleIllegalArgumentException(IllegalArgumentException exception) {
        logger.error("【handleIllegalIllegalArgumentException】：" + exception.getMessage());
        BusinessResult<Object> businessResult = BusinessResult.createInstance(PARMAS_INVALID.getCode(), exception.getMessage());
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(businessResult);
    }

    /**
     * 权限异常处理
     *
     * @param exception exception
     * @return ResponseEntity
     */
    @ExceptionHandler({AccessDeniedException.class})
    public ResponseEntity<BusinessResult<Object>> handleAccessDeniedException(AccessDeniedException exception) {
        logger.error("【handleAccessDeniedException】：" + exception.getMessage());
        BusinessResult<Object> businessResult = BusinessResult.createInstance(NO_AUTH.getCode(), "请传入token，" + exception.getMessage());
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(businessResult);
    }

    @ExceptionHandler({SensitiveException.class})
    public ResponseEntity<BusinessResult<Object>> handleSensitiveException(SensitiveException exception) {
        BusinessResult<Object> businessResult = BusinessResult.createInstance(CON_SENSITIVE.code, "未通过审核，请更换内容后再发布", null);
        sendExceptionUtil.sendException(exception.getMessage());
        return ResponseEntity.status(HttpStatus.OK).body(businessResult);
    }

    /**
     * 业务异常处理
     *
     * @param e
     * @return ResponseEntity
     */
    @ExceptionHandler({Exception.class})
    public ResponseEntity<BusinessResult<Object>> handleException(Exception e, HttpServletRequest request) {

        String method = request.getMethod();
        String uri = request.getRequestURI();
        String paramInfo = "";
        paramInfo = getParam(request, method, paramInfo);
        log.error("API: excepiton={} cause={} method={} uri={} paramInfo={}", e.getClass().getSimpleName(), e.getMessage(), method, uri, paramInfo);
        log.error("", e);
        formatException(e, method, uri, paramInfo);
        BusinessResult<Object> businessResult = BusinessResult.createInstance(CommonResultMessage.DIARY_FAIL.getCode(), e.getMessage());
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(businessResult);
    }


    private String getParam(HttpServletRequest request, String method, String paramInfo) {
        if ("GET".equals(method)) {
            paramInfo = request.getQueryString();
        } else if (("POST".equals(method) || "PUT".equals(method))) {
            String contentType = request.getHeader("Content-Type");
            if (contentType != null && !contentType.contains("multipart")) {
                Map<String, String[]> params = request.getParameterMap();
                if (params != null && params.size() == 0) {
                    paramInfo = HttpHelper.getBodyString(request);
                } else {
                    Map<String, Object> paramsObj = new HashMap<>();
                    for (String key : params.keySet()) {
                        paramsObj.put(key, params.get(key));
                    }
                    try {
                        paramInfo = objectMapper.writeValueAsString(paramsObj);
                    } catch (JsonProcessingException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return paramInfo;
    }

    private void formatException(Exception e, String method, String uri, String paramInfo) {
        sendExceptionUtil.sendException("\n4. [" + method + "]：" + uri + "\n5. [paramInfo]：" + paramInfo + "\n6. [datetime]：" + DateUtil.getStringDate(), e);
    }

    @Autowired
    private ObjectMapper objectMapper;

}
